package kr.pe.johnkim.carrotpoint.mobile.util;

import kr.pe.johnkim.carrotpoint.mobile.domain.ImageFile;
import org.apache.commons.lang.math.JVMRandom;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.encoding.ShaPasswordEncoder;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.PixelGrabber;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;

/**
 * 공통 기능들을 구현한 클래스이다.
 *
 * @author : johnkim <cale9797@gmail.com>
 * @date: 13. 1. 18.
 */
@Component
public class CheckMileageCommon {

    // SLF4J Logging
    private Logger logger = LoggerFactory.getLogger(CheckMileageCommon.class);

    ShaPasswordEncoder encoder = new ShaPasswordEncoder();

    public static JVMRandom random = new JVMRandom();

    /**
     * 입력 받은 암호를 SHA 를 이용 해서 암호화 한 뒤 반환 한다.
     *
     * @param password
     * @return
     */
    public String getEncodedPassword(String password) {
        logger.info("getEncodedPassword");
        return encoder.encodePassword(password, null);
    }

    /**
     * 인증 번호를 넘겨 준다.
     *
     * 고유한 UUID 를 생성한 뒤에 앞 4자리를 잘라서 넘겨 준다.
     *
     * @return
     */
    public String getCertificationNumber() {
        logger.info("getCertificationNumber");
        String uuid = String.valueOf(random.nextInt(999999999));

        return uuid.substring(0, 4);
    }

    /**
     * 현재 날짜와 시간을 2010-10-22 15:20:46 포멧의 string 으로 반환 한다.
     *
     * @return
     */
    public String getCurrentDate() {
        logger.info("getCurrentDate");

        String currentDate = "";

        Date date = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        currentDate = simpleDateFormat.format(date);

        return currentDate;
    }

    /**
     * MultipartFile 로 업로드 된 이미지 파일을 UUID 를 이용 해서 unique 한 파일 명으로 수정한 뒤 서버에 저장 한다.
     * 그 결과를 반환 한다.
     *
     * @param parameter
     * @return
     */
    public ImageFile uploadProfileImage(ImageFile parameter) {
        logger.info("uploadProfileImage");

        InputStream inputStream;

        UUID uuid = UUID.randomUUID();

        String fileName = parameter.getImageFile().getOriginalFilename();
        // "." 을 포함한 파일 확장자를 추출 한다.
        String fileNameSuffix = fileName.substring(fileName.length()-4, fileName.length());

        logger.info("fileName       : {}", fileName);
        logger.info("fileNameSuffix : {}", fileNameSuffix);

        // 파일명 앞에 사용자 아이디를 붙인다.
        String tempFileName = parameter.getCheckMileageId() + "_" + uuid.toString() + fileNameSuffix;

        try {
            inputStream = parameter.getImageFile().getInputStream();

            OutputStream outputStream = new FileOutputStream(parameter.getUploadPath() + tempFileName);

            int bytesRead = 0;
            byte [] buffer = new byte[8192];

            while ((bytesRead = inputStream.read(buffer, 0, 8192)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }

            outputStream.close();
            inputStream.close();
        } catch (Exception e) {
            //
        }

        ImageFile result = new ImageFile();
        result.setFileName(parameter.getImageFile().getOriginalFilename());
        result.setFileSize(Long.toString(parameter.getImageFile().getSize()));
        result.setContentType(parameter.getImageFile().getContentType());
        result.setTempFileName(tempFileName);

        return result;
    }

    /**
     * 해당 사이즈로 썸네일 이미지를 생성 한다.
     * 가로, 세로의 비율에 상관 없이 입력된 size 로 줄인다.
     *
     * @param thumbnailParameter
     * @return
     * @throws IOException
     */
    public String createThumbnailImageFile(ImageFile thumbnailParameter) throws IOException {
        logger.info("createThumbnailImageFile");

        final int RATIO = 0;
        final int SAME = -1;

        Image srcImg = null;
        String suffix = thumbnailParameter.getOriginalImageFile().getName().substring(thumbnailParameter.getOriginalImageFile().getName().lastIndexOf('.')+1).toLowerCase();

        if (suffix.equals("bmp") || suffix.equals("png") || suffix.equals("gif")) {
            srcImg = ImageIO.read(thumbnailParameter.getOriginalImageFile());
        } else {
            // BMP가 아닌 경우 ImageIcon을 활용해서 Image 생성
            // 이렇게 하는 이유는 getScaledInstance를 통해 구한 이미지를
            // PixelGrabber.grabPixels로 리사이즈 할때
            // 빠르게 처리하기 위함이다.
            srcImg = new ImageIcon(thumbnailParameter.getOriginalImageFile().toURL()).getImage();
        }

        int srcWidth = srcImg.getWidth(null);
        int srcHeight = srcImg.getHeight(null);

        int destWidth = -1, destHeight = -1;

        if (thumbnailParameter.getThumbnailWidth() == SAME) {
            destWidth = srcWidth;
        } else if (thumbnailParameter.getThumbnailWidth() > 0) {
            destWidth = thumbnailParameter.getThumbnailWidth();
        }

        if (thumbnailParameter.getThumbnailHeight() == SAME) {
            destHeight = srcHeight;
        } else if (thumbnailParameter.getThumbnailHeight() > 0) {
            destHeight = thumbnailParameter.getThumbnailHeight();
        }

        if (thumbnailParameter.getThumbnailWidth() == RATIO && thumbnailParameter.getThumbnailHeight() == RATIO) {
            destWidth = srcWidth;
            destHeight = srcHeight;
        } else if (thumbnailParameter.getThumbnailWidth() == RATIO) {
            double ratio = ((double)destHeight) / ((double)srcHeight);
            destWidth = (int)((double)srcWidth * ratio);
        } else if (thumbnailParameter.getThumbnailHeight() == RATIO) {
            double ratio = ((double)destWidth) / ((double)srcWidth);
            destHeight = (int)((double)srcHeight * ratio);
        }

        Image imgTarget = srcImg.getScaledInstance(destWidth, destHeight, Image.SCALE_SMOOTH);
        int pixels[] = new int[destWidth * destHeight];
        PixelGrabber pg = new PixelGrabber(imgTarget, 0, 0, destWidth, destHeight, pixels, 0, destWidth);

        try {
            pg.grabPixels();
        } catch (InterruptedException e) {
            throw new IOException(e.getMessage());
        }

        BufferedImage destImg = new BufferedImage(destWidth, destHeight, BufferedImage.TYPE_INT_RGB);
        destImg.setRGB(0, 0, destWidth, destHeight, pixels, 0, destWidth);

        /**
         * PNG 포멧 으로 이미지 파일을 생성 한다.
         * 확장자는 ".png" 를 따로 붙여 주어야 한다.
         */
        ImageIO.write(destImg, "png", thumbnailParameter.getThumbnailImageFile());

        return thumbnailParameter.getThumbnailImageFile().getName();
    }
}
